#include <iostream>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <unistd.h>
#include <cstring>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <memory>
#include "Log.hpp"
#include <sys/types.h>
#include <cerrno>
#include <unordered_map>
#include "RingQueue.hpp"
#include <thread>
#define SIZE 1024
// 将客户端改造成聊天
class UdpServer // 客户端
{
    static void recv(UdpServer* udp)
    {

        static char buffer[SIZE];
        while (true)
        {
            memset(&buffer, 0, sizeof(buffer));
            struct sockaddr_in peer;
            bzero(&peer, sizeof(peer));
            socklen_t len = sizeof(peer);
            ssize_t s = recvfrom(udp->sock_, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
            udp->rq_->push(buffer);
            char key[64]; // 存储客户信息
            if (s > 0)    // 读取成功
            {
                logMessage(NORMAL, "%s", "Server read client Information succeeded");
                buffer[s] = 0;
                // 输出发送的信息
                uint16_t client_port = ntohs(peer.sin_port);
                std::string client_ip = inet_ntoa(peer.sin_addr);
                snprintf(key, sizeof(key), "[%s:%d]", client_ip.c_str(), client_port);
                logMessage(NORMAL, "key:%s", key);
                // printf("[%s:%d]# %s\n",client_ip.c_str(),client_port,buffer);
                auto it = udp->users_.find(key);
                if (it == udp->users_.end()) // 第一次添加
                {
                    logMessage(NORMAL, "add new user : %s", key);
                    udp->users_.insert({key, peer});
                }
            }
        }
    }
    static void send(UdpServer* udp)
    {
        while (true)
        {
            std::string tmp;
            udp->rq_->pop(&tmp);
            for (auto &iter : udp->users_)
            {
                std::string server_message = iter.first.c_str();
                server_message += "# ";
                server_message += tmp;
                sendto(udp->sock_, server_message.c_str(), server_message.size(), 0, (struct sockaddr *)&(iter.second), sizeof(iter.second));
                logMessage(NORMAL, "%s", "Server returned the client information succeeded");
            }
        }
    }

public:
    UdpServer(uint16_t port, std::string ip = "") : port_(port), ip_(ip), sock_(-1) // ip一般不需要显示输入，服务器在工作中可以从任意IP中获取数据
    {
        rq_ = new RingQueue<std::string>();
    }
    bool initServer() // 初始化服务器
    {
        // 1.创建套接字
        sock_ = socket(AF_INET, SOCK_DGRAM, 0); // 用于网络的套接字,AF_INET == PF_INER
        if (sock_ < 0)                          // 创建套接字失败
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(1);
        }
        // 2.bind：将用户设置的ip和port与当前进程强关联
        // 注意：需要将string类型的IP地址（点分十进制）转换为4字节的整形
        struct sockaddr_in local;
        // 内存清零
        bzero(&local, sizeof(local));
        local.sin_family = AF_INET;
        // 服务器的端口号和ip也要发送到网络中
        local.sin_port = htons(port_); // 本地转换到网络格式（大小端）
        /// inet_addr(ip)//将字符类型的ip地址转换为4字节，然后再转换为网络的存储格式
        local.sin_addr.s_addr = ip_.empty() ? INADDR_ANY : inet_addr(ip_.c_str());
        if (bind(sock_, (struct sockaddr *)&local, sizeof(local)) < 0) // 绑定失败
        {
            logMessage(FATAL, "%d:%s", errno, strerror(errno));
            exit(2);
        }
        logMessage(NORMAL, "%s", "init udp server done...");
        return true;
    }
    void Start() // 服务器启动
    {
        // char buffer[SIZE];
        //  服务器永远不退出
        std::thread Accept(recv,this);
        std::thread Sender(send,this);
        Accept.join();
        Sender.join();
        //while(true)
        //{
        // // peer纯输出型参数
        // struct sockaddr_in peer;
        // bzero(&peer, sizeof(peer));
        // socklen_t len = sizeof(peer);
        // //(1)读取数据
        // ssize_t s = recvfrom(sock_, buffer, sizeof(buffer) - 1, 0, (struct sockaddr *)&peer, &len);
        // char key[64]; // 存储客户信息
        // if (s > 0)    // 读取成功
        // {
        //     logMessage(NORMAL, "%s", "Server read client Information succeeded");
        //     buffer[s] = 0;
        //     // 输出发送的信息
        //     uint16_t client_port = ntohs(peer.sin_port);
        //     std::string client_ip = inet_ntoa(peer.sin_addr);
        //     snprintf(key, sizeof(key), "[%s:%d]", client_ip.c_str(), client_port);
        //     logMessage(NORMAL, "key:%s", key);
        //     // printf("[%s:%d]# %s\n",client_ip.c_str(),client_port,buffer);
        //     auto it = users_.find(key);
        //     if (it == users_.end()) // 第一次添加
        //     {
        //         logMessage(NORMAL, "add new user : %s", key);
        //         users_.insert({key, peer});
        //     }
        // }
        // // 服务器对其加工
        // for (auto &iter : users_)
        // {
        //     std::string server_message = key;
        //     server_message+="# ";
        //     server_message += buffer;
        //     sendto(sock_, server_message.c_str(), server_message.size(), 0, (struct sockaddr *)&(iter.second), sizeof(iter.second));
        //     logMessage(NORMAL, "%s", "Server returned the client information succeeded");
        // }
       // }
    }
    ~UdpServer()
    {
        if (sock_ >= 0)
            close(sock_);
        delete rq_;
        logMessage(NORMAL, "%s", "Server shutdown");
    }

private:
    // 服务器需要端口号和ip地址
    uint16_t port_;                                             // 端口号
    std::string ip_;                                            // ip地址
    int sock_;                                                  // 套接字
    std::unordered_map<std::string, struct sockaddr_in> users_; // 映射客户端信息
    RingQueue<std::string> *rq_;                                // 环形消息队列
};